//
// Created by wxd on 2025/6/29.
// 引擎的全局日志库
//

#ifndef LOGGER_H
#define LOGGER_H

#pragma once

#include <string>
#include <fstream>
#include <iomanip>
#include <mutex>
#include <atomic>
#include <filesystem>

// 日志级别枚举
enum class LogLevel {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL,
    OFF
};

class Logger {
public:
    // 删除拷贝构造和赋值构造
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    // 静态单例
    static Logger& getInstance();

    // 日志的初始化
    void init(LogLevel level = LogLevel::INFO, const std::string& fileName = "", bool consoleOutput = true, bool fileOutput = false);

    // 设置日志级别
    void setLevel(LogLevel level);

    // 获取当前日志级别
    LogLevel getLevel() const;

    // 日志输出: 日志级别，包名，文件名，类名，函数名，函数执行的行号，自定义日志消息
    void log(LogLevel level,
             const std::string& package,
             const std::string& currentFile,
             const std::string& className,
             const std::string& function,
             int line,
             const std::string& message);

    // 日志输出: 日志级别，包名，文件名，函数名，函数执行的行号，自定义日志消息
    void log(LogLevel level,
             const std::string& package,
             const std::string& currentFile,
             const std::string& function,
             int line,
             const std::string& message);

    // 刷新缓冲区
    void flush();

    // 是否初始化
    bool isInitialized() const;

private:
    Logger();
    ~Logger();

    // 获取当前的时间
    [[nodiscard]] std::string getCurrentTime() const;

    // 日志级别转化为字符串
    [[nodiscard]] std::string logLevel2String(LogLevel level) const;

    // 线程id转化为字符串
    [[nodiscard]] std::string threadId2String() const;

    LogLevel m_Level;                           // 当前的日志级别
    std::ofstream m_FileStream;                 // 文件输出流
    bool m_ConsoleOutput;                       // 是否输出控制台
    bool m_FileOutput;                          // 是否记录文件
    std::mutex m_Mutex;                         // 互斥锁抱枕线程安全
    std::atomic<bool> m_Initialized;            // 是否已经初始化
};

// 提取文件名, 函数名，行号
#define _GL_FILENAME_       std::filesystem::path(__FILE__).filename().string()
#define _GL_FUNC_NAME_      __FUNCTION__
#define _GL_LINE_ID_        __LINE__
#define _GL_CLASS_NAME_     _GL_CLASS_NAME_


/*********************************************************方法日志宏*****************************************************/
#define LOG_TRACE_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::TRACE, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_INFO_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::INFO, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_DEBUG_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::DEBUG, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_WARN_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::WARN, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_ERROR_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::ERROR, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_FATAL_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::FATAL, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_OFF_METHOD(package, message) \
    Logger::getInstance().log(LogLevel::OFF, package, _GL_FILENAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)


/*********************************************************类日志宏******************************************************/
#define LOG_TRACE_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::TRACE, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_INFO_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::INFO, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_DEBUG_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::DEBUG, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_WARN_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::WARN, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_ERROR_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::ERROR, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_FATAL_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::FATAL, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)

#define LOG_OFF_CLASS(package, message) \
    Logger::getInstance().log(LogLevel::OFF, package, _GL_FILENAME_, _GL_CLASS_NAME_, _GL_FUNC_NAME_, _GL_LINE_ID_, message)


/********************************************通过宏来控制调用method-log还是class-log***************************************/
/*#if __cplusplus >= 201703L
#define LOG_TRACE(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)>) \
        return LOG_TRACE_CLASS(package, message); \
    else \
        return LOG_TRACE_METHOD(package, message); \
}())
#else
#define LOG_TRACE(package, message) LOG_TRACE_METHOD(package, message)
#endif


#if __cplusplus >= 201703L
#define LOG_DEBUG(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)>) \
        return LOG_DEBUG_CLASS(package, message); \
    else \
        return LOG_DEBUG_METHOD(package, message); \
}())
#else
#define LOG_DEBUG(package, message) LOG_TRACE_METHOD(package, message)
#endif


#if __cplusplus >= 201703L
#define LOG_INFO(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)>) \
        return LOG_INFO_CLASS(package, message); \
    else \
        return LOG_INFO_METHOD(package, message); \
}())
#else
#define LOG_INFO(package, message) LOG_TRACE_METHOD(package, message)
#endif


#if __cplusplus >= 201703L
#define LOG_WARN(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)>) \
        return LOG_WARN_CLASS(package, message); \
    else \
        return LOG_WARN_METHOD(package, message); \
}())
#else
#define LOG_WARN(package, message) LOG_TRACE_METHOD(package, message)
#endif


#if __cplusplus >= 201703L
#define LOG_ERROR(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)> \
        return LOG_ERROR_CLASS(package, message); \
    else \
        return LOG_ERROR_METHOD(package, message); \
#else
#define LOG_ERROR(package, message) LOG_ERROR_METHOD(package, message)
#endif


#if __cplusplus >= 201703L
#define LOG_FATAL(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)> \
        return LOG_FATAL_CLASS(package, message); \
    else \
        return LOG_FATAL_METHOD(package, message); \
#else
#define LOG_FATAL(package, message) LOG_FATAL_METHOD(package, message)
#endif


#if __cplusplus >= 201703L
#define LOG_OFF(package, message) \
([] { \
    if constexpr (std::is_member_pointer_v<decltype(this)> \
        return LOG_OFF_CLASS(package, message); \
    else \
        return LOG_OFF_METHOD(package, message); \
#else
#define LOG_OFF(package, message) LOG_OFF_METHOD(package, message)
#endif*/


#endif // LOGGER_H



